package com.allwees.support.marketing.handler;

import com.alibaba.fastjson.JSONObject;
import com.allwees.bs.core.model.constant.CacheName;
import com.allwees.bs.core.model.product.entity.ProductModel;
import com.allwees.bs.core.model.product.entity.SkuModel;
import com.allwees.bs.core.model.util.PriceShouldAdjusted;
import com.allwees.core.cache.RedisUtil;
import com.allwees.core.mq.rabbitmq.MqUtil;
import com.allwees.support.marketing.constant.AdjustPriceRuleCode;
import com.allwees.support.marketing.domain.AdjustPriceRule;
import com.allwees.support.marketing.event.PriceRuleUpdatedEvent;
import com.allwees.support.marketing.service.AdjustPriceRuleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @Author Daniel
 * @Version 1.0.0
 * @Description
 * @CreateTime 2020/9/2 16:32
 */
@Slf4j
@Component
public class PriceAdjustor {

    @Resource
    private AdjustPriceRuleService adjustPriceRuleService;

    private static final Map<AdjustPriceRuleCode, List<PriceRuleHolder>> RULES_MAP = new ConcurrentHashMap<>();

    @PostConstruct
    public void init(){
        List<PriceRuleHolder> list;
        for (AdjustPriceRule rule : adjustPriceRuleService.list()) {
            if(rule.isValid()){
                list = JSONObject
                        .parseObject(rule.getRuleContent())
                        .entrySet()
                        .stream()
                        .map(PriceRuleHolder::new)
                        .sorted(Comparator.comparing(PriceRuleHolder::getMinPrice))
                        .collect(Collectors.toList());
            } else {
                list = Collections.emptyList();
            }
            RULES_MAP.put(rule.getRuleCode(),list);
        }
    }

    @TransactionalEventListener
    public void priceRuleUpdated(PriceRuleUpdatedEvent event){
        MqUtil.send(event.getExchange(),"",event.getSource());
    }

    public static<T extends PriceShouldAdjusted> void adjustPrice(List<T> beans){
        beans.forEach(PriceAdjustor::adjustPrice);
    }

    public static <T extends PriceShouldAdjusted> void adjustPrice(T bean) {
        if (bean == null) {
            return;
        }

        PriceRuleHolder ruleHolder;
        for (AdjustPriceRuleCode ruleCode : AdjustPriceRuleCode.values()) {
            if(ruleCode == AdjustPriceRuleCode.SHIPPING_FEE) {
                ruleHolder = getRuleHolder(RULES_MAP.get(ruleCode), bean, bean.getShippingPrice());
                //sku | spu调价后的运费
                bean.setPriceShip(ruleHolder.applyRule(bean.getShippingPrice()));
                continue;
            }
            //以售价为基础找出来的calculator来计算调节后的售价和原价以保证涨幅一致
            ruleHolder = getRuleHolder(RULES_MAP.get(ruleCode), bean, bean.getRetailPrice());
            //sku | spu 调价后的售价
            bean.setPriceRetail(ruleHolder.applyRule(bean.getRetailPrice()));
            //sku | spu 调价后的原价
            bean.setPriceOrigin(ruleHolder.applyRule(bean.getOriginalPrice()));
        }
    }

    /**
     *  1.未配置加价规则
     *  2.商品禁止加价
     *  3.配置的加价规则
     * @param ruleHolders
     * @param bean
     * @param price
     * @return
     */
    private static PriceRuleHolder getRuleHolder(List<PriceRuleHolder> ruleHolders, PriceShouldAdjusted bean,BigDecimal price){
        PriceRuleHolder ruleHolder = tryGetDefault(ruleHolders, bean);
        if(ruleHolder != null){
            return ruleHolder;
        }
        //3.匹配已配置的加价规则
        return ruleHolders
                .stream()
                .filter(rule -> rule.match(price))
                .findFirst()
                .orElse(PriceRuleHolder.getDefault());
    }


    private static PriceRuleHolder tryGetDefault(List<PriceRuleHolder> ruleHolders,PriceShouldAdjusted bean){
        //1.未配置加价规则
        if (CollectionUtils.isEmpty(ruleHolders)) {
            return PriceRuleHolder.getDefault();
        }
        String productUuid;
        if(bean instanceof SkuModel){
            productUuid = ((SkuModel) bean).getProductUuid();
        } else {
            productUuid = ((ProductModel) bean).getUuid();
        }
        //2.商品禁止加价
        if(isForbidden(productUuid)){
            return PriceRuleHolder.getDefault();
        }
        return null;
    }

    private static boolean isForbidden(String productUuid){
        return RedisUtil.hexists(CacheName.PROD_FORBID_ADJUST_PRICE,productUuid);
    }

    /**
     * 根据加价后的价格计算出原来的价格，用于对数据库中spu的过滤
     * @param priceRetail
     * @return
     */
    public static BigDecimal getRetailPrice(BigDecimal priceRetail) {
        if (priceRetail == null || priceRetail.compareTo(BigDecimal.ZERO) == 0) {
            return priceRetail;
        }
        Predicate<PriceRuleHolder> filter = r -> r.ominPrice.compareTo(priceRetail) <= 0 && r.omaxPrice.compareTo(priceRetail) > 0;
        PriceRuleHolder holder = RULES_MAP
                        .get(AdjustPriceRuleCode.PRODUCT_PRICE)
                        .stream()
                        .sorted(Comparator.comparing(PriceRuleHolder::getMinPrice).reversed())
                        .filter(filter)
                        .findFirst()
                        .orElse(PriceRuleHolder.getDefault());
        BigDecimal retailPrice = holder.parser.apply(priceRetail);
        log.info(">>>price after adjust:{},retail price calculated:{}",priceRetail,retailPrice);
        return retailPrice;
    }
}
